package com.zb.nio.buffer;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

import org.junit.Test;

/**
 * @author: zhaobin
 * @date: 2024/1/3 16:16
 * @Description:
 */
public class BufferDemo2 {

    /**
     * 缓冲区分片
     */
    @Test
    public void slice() {
        // 创建Buffer
        IntBuffer buf = IntBuffer.allocate(10);
        // 写入
        for (int i = 0; i < buf.capacity(); i++) {
            buf.put(i);
        }

        // 创建子缓冲区
        buf.position(3);
        buf.limit(7);
        IntBuffer sliceBuf = buf.slice();
        // 子缓冲区写入
        for (int i = 0; i < sliceBuf.capacity(); i++) {
            int s = sliceBuf.get(i);
            s *= 10;
            sliceBuf.put(s);
        }
        // 输出
        buf.position(0);
        buf.limit(buf.capacity());
        while(buf.remaining() > 0){
            System.out.print(buf.get() + " ");
        }
    }

    /**
     * 只读缓冲区
     */
    @Test
    public  void readOnlyBuffer() {
        // 创建Buffer
        IntBuffer buf = IntBuffer.allocate(10);
        // 写入
        for (int i = 0; i < buf.capacity(); i++) {
            buf.put(i);
        }

        // 得到只读缓冲区
        IntBuffer readOnlyBuffer = buf.asReadOnlyBuffer();
        // 不能向只读缓冲区写数据，会抛异常
//        for (int i = 0; i < readOnlyBuffer.capacity(); i++) {
//            readOnlyBuffer.put(i*10);
//        }

        // 写入新数据
        for (int i = 0; i < buf.capacity(); i++) {
            buf.put(i,i * 10);
        }

        // 重新新位置
        readOnlyBuffer.position(0);
        readOnlyBuffer.limit(readOnlyBuffer.capacity());
        System.out.println("只读buf位置："+readOnlyBuffer.position() + " " + readOnlyBuffer.limit());
        // 输出
        while(readOnlyBuffer.hasRemaining()){
            System.out.print(readOnlyBuffer.get() + " ");
        }
    }

    /**
     * 直接缓冲区
     * @throws IOException
     */
    @Test
    public void bufferDirect() throws IOException {
        // 输入通道
        String inFilePath = "file/04.txt";
        FileInputStream fis = new FileInputStream(inFilePath);
        FileChannel fiChannel = fis.getChannel();

        // 输出通道
        String outFilePath = "file/04_.txt";
        FileOutputStream fos = new FileOutputStream(outFilePath);
        FileChannel foChannel = fos.getChannel();

        // 创建直接缓冲区
        ByteBuffer buf = ByteBuffer.allocateDirect(64);

        // 复制
        long a = fiChannel.size();
        int b = buf.capacity();
        System.out.println("文件大小：" + a + "字节");
        System.out.println("缓冲区大小：" + b + "字节");
        System.out.println("共需要复制：" + (int)Math.ceil(a/(float)b));
        int i = 0;
        // 如果还有数据可以写入buf，就循环操作
        while (fiChannel.read(buf) != -1) {
            i++;
            // 读写反转
            buf.flip();
            // 从buf中读取数据，写入通道，并存入文件
            foChannel.write(buf);
            // 清空buf
            buf.clear();
        }
        System.out.println("实际复制次数：" + i);
        System.out.println("复制完成");

        // 关闭
        fiChannel.close();
        foChannel.close();
    }

    @Test
    public void mapIO() throws IOException {
        int start = 0;
        int size = 1024;

        RandomAccessFile raf = new RandomAccessFile("file/04.txt", "rw");
        FileChannel fc = raf.getChannel();
        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, start, size);

        mbb.put(0, (byte) 97);
        mbb.put(1023, (byte) 122);

        fc.close();
    }



}
